﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="frmMainPartial.cs" company="SmartPlan">
//   SmartPlan 2011
// </copyright>
// <summary>
//   Defines the FrmMain type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

 #define Async

namespace DbDiff.WinClient.Forms
{
    using System;
    using System.Linq;
    using System.Windows.Forms;
    using DbDiff.Common.Comparer;
    using DbDiff.Common.DataAccess;
    using DbDiff.Common.Helper;
    using DbDiff.Common.Model;
    using DbDiff.WinClient.BusinessObjects;
    using DbDiff.WinClient.Forms.DbItems;
    using DbDiff.WinClient.Forms.Status;
    using DbDiff.WinClient.Helper;

    /// <summary>
    /// The main form
    /// </summary>
    public partial class FrmMain : Form
    {
        /// <summary>
        /// The update form view.
        /// </summary>
        private void UpdateFormView()
        {
            this.UpdateFormTitle();

            this.menuItemToolBar.Checked = ConfigInstance.Config.IsToolBar;
            this.menuItemStatusBar.Checked = ConfigInstance.Config.IsStatusBar;
            this.menuItemViewRegisteredServers.Checked = ConfigInstance.Config.IsRegisteredServersVisible;

            this.maindToolbar.Visible = ConfigInstance.Config.IsToolBar;
            this.mainStatusBar.Visible = ConfigInstance.Config.IsStatusBar;

            this.tabControlDatabaseInfo.TabPages.Clear();

            if ((!this.Databases.DatabaseLeft.IsConnected) &&
                (!this.Databases.DatabaseRight.IsConnected))
            {
                this.panelLeft.Visible = false;
                this.splitterMain.Visible = false;
                this.panelList.Controls.Clear();
            }
            else
            {
                this.panelLeft.Visible = true;
                this.splitterMain.Visible = true;
                this.panelList.Visible = true;

                if (ConfigInstance.Config.IsRegisteredServersVisible)
                {
                    this.tabControlDatabaseInfo.TabPages.Add(this.tabPageServers);
                }

                if (this.Databases.DatabaseLeft.IsConnected)
                {
                    this.tabControlDatabaseInfo.TabPages.Add(this.tabPageDatabase1);
                }

                if (this.Databases.DatabaseRight.IsConnected)
                {
                    this.tabControlDatabaseInfo.TabPages.Add(this.tabPageDatabase2);
                }

                if (this.Databases.IsCompared)
                {
                    this.tabControlDatabaseInfo.TabPages.Add(this.tabPageDiff);
                }
            }

            this.tbbReloadDb1.Enabled = this.Databases.DatabaseLeft.IsConnected;
            this.tbbCloseDb1.Enabled = this.Databases.DatabaseLeft.IsConnected;
            this.menuItemReloadDb1.Enabled = this.Databases.DatabaseLeft.IsConnected;
            this.menuItemCloseDb1.Enabled = this.Databases.DatabaseLeft.IsConnected;

            this.tbbReloadDb2.Enabled = this.Databases.DatabaseRight.IsConnected;
            this.tbbCloseDb2.Enabled = this.Databases.DatabaseRight.IsConnected;
            this.menuItemReloadDb2.Enabled = this.Databases.DatabaseRight.IsConnected;
            this.menuItemCloseDb2.Enabled = this.Databases.DatabaseRight.IsConnected;

            bool compareIsEnabled = this.Databases.DatabaseLeft.IsConnected &&
                                    this.Databases.DatabaseRight.IsConnected;
            this.menuItemCompare.Enabled = compareIsEnabled;
            this.tbbCompare.Enabled = compareIsEnabled;
            this.tbbAlterScript1.Enabled = compareIsEnabled && this.Databases.IsCompared;
            this.menuItemAlterScript1.Enabled = compareIsEnabled && this.Databases.IsCompared;
            this.tbbAlterScript2.Enabled = compareIsEnabled && this.Databases.IsCompared;
            this.menuItemAlterScript2.Enabled = compareIsEnabled && this.Databases.IsCompared;
        }

        /// <summary>
        /// The update form data.
        /// </summary>
        private void UpdateFormData()
        {
            this.ShowRegisteredServers();
        }

        /// <summary>
        /// The update form title.
        /// </summary>
        private void UpdateFormTitle()
        {
            string projectTitle = this.project.Name;
            if (this.project.IsChanged)
            {
                projectTitle += "*";
            }

            this.Text = string.Format(ConfigInstance.Config.DebugMode ? "DBDiff - ({0}) - [DEBUG MODE]" : "DBDiff - ({0})", projectTitle);
        }

        /// <summary>
        /// The show registered servers.
        /// </summary>
        private void ShowRegisteredServers()
        {
            if (!ConfigInstance.Config.IsRegisteredServersVisible)
            {
                return;
            }

            this.serversTreeView.Nodes.Clear();

            this.serversTreeView.Nodes.Add(new TreeNode("Registered servers") { Tag = "root" });

            foreach (RegisteredServer server in ConfigInstance.Config.RegisteredServers)
            {
                this.serversTreeView.Nodes[0].Nodes.Add(new TreeNode(server.Id) { Tag = server });
            }

            this.serversTreeView.ExpandAll();
        }

        /// <summary>
        /// The update status bar.
        /// </summary>
        /// <param name="txt">
        /// The txt for updating
        /// </param>
        public void UpdateStatusBar(string txt)
        {
            this.mainStatusBar.Text = txt;
        }

        /// <summary>
        /// Showing node and object properties
        /// </summary>
        /// <param name="index">
        /// start index
        /// </param>
        /// <param name="e">
        /// The tree event arguments
        /// </param>
        private void ShowItem2(int index, TreeViewEventArgs e)
        {
            // Ha éppen feltöltés alatt van valamelyik adatbázis, akkor lépjen ki!
            if (((index == 0) && this.Databases.DatabaseLeft.IsUnderFill) ||
                ((index != 0) && this.Databases.DatabaseRight.IsUnderFill))
            {
                return;
            }
        }

        /// <summary>
        /// Megjeleníti a kiválasztott node -hoz tartozó elem tulajdonságait
        /// </summary>
        /// <param name="index">
        /// start index
        /// </param>
        /// <param name="e">
        /// The tree event arguments
        /// </param>
        private void ShowItem(int index, TreeViewEventArgs e)
        {
            // Ha éppen feltöltés alatt van valamelyik adatbázis, akkor lépjen ki!
            if (((index == 0) && this.Databases.DatabaseLeft.IsUnderFill) ||
                ((index != 0) && this.Databases.DatabaseRight.IsUnderFill))
            {
                return;
            }

            try
            {
                this.Cursor = Cursors.WaitCursor;
                if (e.Node.Tag is TagInfo2)
                {
                    var tagInfo = (TagInfo2)e.Node.Tag;
                    string[] objectProp = e.Node.Text.Split(new[] { '.' });
                    string schemaName = string.Empty;
                    string objectName = string.Empty;
                    UcDbItemBase view = null;


                    switch (objectProp.Length)
                    {
                        case 0:
                            break;
                        case 1:
                            objectName = objectProp[0];
                            break;
                        default:
                            schemaName = objectProp[0];
                            objectName = objectProp[1];
                            break;
                    }

                    // if objectProp.Lenth == 0 és nincs difflista, akkor ne mutasson egyenlore semmit 
                    switch (tagInfo.NodeType)
                    {
                        case DatabaseObjectTypes.Server:
                            if ((tagInfo.View == null) &&
                                (!tagInfo.IsLeaf))
                            {
                                view = new UcServer((DatabaseInfo)tagInfo.Item);
                                this.panelList.Controls.Add(view);
                            }

                            break;

                        case DatabaseObjectTypes.Database:
                            if ((tagInfo.View == null) &&
                                (!tagInfo.IsLeaf))
                            {
                                view = new UcDatabase((DatabaseInfo)tagInfo.Item);
                                this.panelList.Controls.Add(view);
                            }

                            break;

                        case DatabaseObjectTypes.Table:
                            if ((tagInfo.View == null) &&
                                (!tagInfo.IsLeaf))
                            {
                                view = new UcTable((DatabaseInfo)tagInfo.Item);
                                this.panelList.Controls.Add(view);
                            }

                            break;

                        case DatabaseObjectTypes.View:
                            if ((tagInfo.View == null) &&
                                (!tagInfo.IsLeaf))
                            {
                                view = new UcExec((DatabaseInfo)tagInfo.Item, "Views", tagInfo.NodeType);
                                this.panelList.Controls.Add(view);
                            }

                            break;

                        case DatabaseObjectTypes.Procedure:
                            if ((tagInfo.View == null) &&
                                (!tagInfo.IsLeaf))
                            {
                                view = new UcExec((DatabaseInfo)tagInfo.Item, "Stored procedures", tagInfo.NodeType);
                                this.panelList.Controls.Add(view);
                            }

                            break;

                        case DatabaseObjectTypes.Function:
                            if ((tagInfo.View == null) &&
                                (!tagInfo.IsLeaf))
                            {
                                view = new UcExec((DatabaseInfo)tagInfo.Item, "Functions", tagInfo.NodeType);
                                this.panelList.Controls.Add(view);
                            }

                            break;

                        case DatabaseObjectTypes.Trigger:
                            if ((tagInfo.View == null) &&
                                (!tagInfo.IsLeaf))
                            {
                                view = new UcExec((DatabaseInfo)tagInfo.Item, "Triggers", tagInfo.NodeType);
                                this.panelList.Controls.Add(view);
                            }

                            break;
                        case DatabaseObjectTypes.User:
                            if ((tagInfo.View == null) &&
                                (!tagInfo.IsLeaf))
                            {
                                view = new UcExec((DatabaseInfo)tagInfo.Item, "Users", tagInfo.NodeType);
                                this.panelList.Controls.Add(view);
                            }

                            break;
                        case DatabaseObjectTypes.Default:
                            if ((tagInfo.View == null) &&
                                (!tagInfo.IsLeaf))
                            {
                                view = new UcExec((DatabaseInfo)tagInfo.Item, "Defaults", tagInfo.NodeType);
                                this.panelList.Controls.Add(view);
                            }

                            break;


                        // case dbObjectsTable.tblRole:
                        //    if (tagInfo.View == null)
                        //    {
                        //        UcDbItemBase roleView = new roleView((DatabaseInfo)tagInfo.Item);
                        //        roleView.Dock = DockStyle.Fill;
                        //        panelList.Controls.Add(roleView);
                        //        tagInfo.View = roleView;
                        //    }
                        // break;

                        case DatabaseObjectTypes.Rule:
                            if ((tagInfo.View == null) &&
                                (!tagInfo.IsLeaf))
                            {
                                view = new UcExec((DatabaseInfo)tagInfo.Item, "Rules", tagInfo.NodeType);
                                this.panelList.Controls.Add(view);
                            }

                            break;
                        case DatabaseObjectTypes.UDT:
                            if ((tagInfo.View == null) &&
                                (!tagInfo.IsLeaf))
                            {
                                view = new UcExec((DatabaseInfo)tagInfo.Item, "User defined data types", tagInfo.NodeType);
                                this.panelList.Controls.Add(view);
                            }

                            break;
                    }

                    if (tagInfo.View == null)
                    {
                        if (tagInfo.IsLeaf)
                        {
                            // egy elem
                            if (this.viewList.Contains(tagInfo.NodeType))
                            {
                                view = (UcDbItemBase)this.viewList[tagInfo.NodeType];
                                ((UcItemDetailsContainer)view).SetData((DatabaseInfo)tagInfo.Item, tagInfo.NodeType, schemaName, objectName);
                            }
                            else
                            {
                                view = new UcItemDetailsContainer((DatabaseInfo)tagInfo.Item, tagInfo.NodeType, schemaName, objectName);
                                this.viewList.Add(tagInfo.NodeType, view);
                                this.panelList.Controls.Add(view);
                            }
                        }

                        tagInfo.View = view;
                    }
                    else
                    {
                        if (tagInfo.IsLeaf)
                        {
                            ((UcItemDetailsContainer)tagInfo.View).SetData((DatabaseInfo)tagInfo.Item, tagInfo.NodeType, schemaName, objectName);
                        }
                    }

                    if ((tagInfo.View.ToolBar != null) && (tagInfo.View.ToolBar.Buttons.Count > 0))
                    {
                        tagInfo.View.ToolBar.Dock = DockStyle.Top;
                        tagInfo.View.ToolBar.Visible = true;
                        this.Controls.Add(tagInfo.View.ToolBar);
                        this.maindToolbar.SendToBack();
                    }
                    else
                    {
                        for (int i = 0; i < this.Controls.Count; i++)
                        {
                            if ((!(this.Controls[i] is ToolBar)) || (this.Controls[i].Name == this.maindToolbar.Name))
                            {
                                continue;
                            }

                            this.Controls[i].Visible = false;
                            this.Controls.RemoveAt(i);
                        }
                    }

                    if (tagInfo.View is UcDbItemListDetailsBase)
                    {
                        if (((UcDbItemListDetailsBase)tagInfo.View).HasFilter)
                        {
                            this.tbbFilter.Visible = true;
                            this.tbbFilter.Pushed = ((UcDbItemListDetailsBase)tagInfo.View).IsFilterVisible;
                        }
                        else
                        {
                            this.tbbFilter.Visible = false;
                        }
                    }

                    tagInfo.View.BringToFront();
                    tagInfo.View.Dock = DockStyle.Fill;
                    tagInfo.View.Visible = true;
                    tagInfo.View.ShowView();
                }
            }
            catch (Exception ex)
            {
                var errorForm = new FrmError(ex);
                errorForm.ShowDialog();
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// Betölti és megjeleníti az adatbázis elemeit
        /// </summary>
        /// <param name="index">
        /// adatbázis index - 1,2
        /// </param>
        /// <param name="mustLoad">
        /// be kell tölteni?
        /// </param>
        private void ShowDatabase(SelectedDatabase index, bool mustLoad)
        {
            TreeNode databaseNode;
            TreeNode serverNode;
            DatabaseInfo currentDb;
            TreeView currentTv;

            try
            {
                this.Cursor = Cursors.WaitCursor;
                switch (index)
                {
                    case SelectedDatabase.Left:
                        if (!this.Databases.DatabaseLeft.IsConnected)
                        {
                            return;
                        }

                        currentDb = this.Databases.DatabaseLeft;
                        currentTv = this.databaseTreeView1;
                        break;

                    case SelectedDatabase.Right:
                        if (!this.Databases.DatabaseRight.IsConnected)
                        {
                            return;
                        }
                        currentDb = this.Databases.DatabaseRight;
                        currentTv = this.databaseTreeView2;
                        break;

                    default:
                        throw new DbDiffClientException("ERROR: Invalid database index! Index: " + index);
                }

                if (mustLoad)
                {
                    this.GetDatabaseItems(index, currentDb);
                }

                currentTv.Nodes.Clear();
                currentTv.HideSelection = false;

                serverNode = new TreeNode(string.Format("Server: {0}", currentDb.Server.Name))
                {
                    ImageIndex = 0,
                    SelectedImageIndex = 0,
                    Tag = new TagInfo2(DatabaseObjectTypes.Server, currentDb, null)
                };
                currentTv.Nodes.Add(serverNode);

                databaseNode = new TreeNode("Database: " + currentDb.Name + " (reg. server: " + currentDb.Server.Id + ")")
                {
                    ImageIndex = 2,
                    SelectedImageIndex = 2,
                    Tag = new TagInfo2(DatabaseObjectTypes.Database, currentDb, null)
                };
                
                serverNode.Nodes.Add(databaseNode);

                currentTv.ExpandAll();

                TreeNode node;
                if (ConfigInstance.Config.IsTablesVisible)
                {
                    node = this.ShowOneResult(databaseNode, "Tables", DatabaseObjectTypes.Table, 3, currentDb);
                    foreach (DbObjectsDs._TableRow tableRow in currentDb.GetRawDatatable(DatabaseObjectTypes.Table).Rows)
                    {
                        this.ShowMoreNode(node, currentDb, 4, DatabaseObjectTypes.Table, string.Format("{0}.{1}", tableRow.SchemaName, tableRow.TableName));
                    }
                }

                if (ConfigInstance.Config.IsViewsVisible)
                {
                    node = this.ShowOneResult(databaseNode, "Views", DatabaseObjectTypes.View, 3, currentDb);
                    foreach (DbObjectsDs.ViewRow viewRow in currentDb.GetRawDatatable(DatabaseObjectTypes.View).Rows)
                    {
                        this.ShowMoreNode(node, currentDb, 4, DatabaseObjectTypes.View, string.Format("{0}.{1}", viewRow.SchemaName, viewRow.Name));
                    }
                }

                databaseNode.Nodes.Add(this.AddProgrammabilty(currentDb));
                databaseNode.Nodes.Add(this.AddSecurityNode(currentDb));

                // currentTv.ExpandAll();
                currentTv.SelectedNode = currentTv.Nodes[0];
            }
            catch (Exception e)
            {
                var errorForm = new FrmError(e);
                errorForm.ShowDialog();
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// Add scurity node
        /// </summary>
        /// <param name="currentDb">
        /// The current db.
        /// </param>
        /// <returns>
        /// The security node
        /// </returns>
        private TreeNode AddSecurityNode(DatabaseInfo currentDb)
        {
            TreeNode node;

            var securityNode = new TreeNode("Security")
                {
                    ImageIndex = 2,
                    SelectedImageIndex = 2,
                    Tag = "Security"
                };

            if (ConfigInstance.Config.IsUsersVisible)
                {
                    node = this.ShowOneResult(securityNode, "Users", DatabaseObjectTypes.User, 3, currentDb);
                    foreach (DbObjectsDs.UserRow row in currentDb.GetRawDatatable(DatabaseObjectTypes.User).Rows)
                    {
                        this.ShowMoreNode(node, currentDb, 4, DatabaseObjectTypes.User, row.Name);
                    }
                }

            if (ConfigInstance.Config.IsRolesVisible)
            {
                node = new TreeNode("Roles");

                // dbNode.Tag = new TagInfo2(dbObjectsTable.tblRole, currentDb, null);
                securityNode.Nodes.Add(node);
                // foreach (DbObjectsDs.tblRoleRow row in currentDb.DatabaseObject.dbObj.dtObjects.Tables[dbObjectsTable.tblRole.ToString()].Rows) 
                // 	dbNode.Nodes.Add(new TreeNode (row.Name));
            }

            securityNode.Nodes.Add(new TreeNode("Schemas"));
            securityNode.Nodes.Add(new TreeNode("Assymetric Keys"));
            securityNode.Nodes.Add(new TreeNode("Certificates"));
            securityNode.Nodes.Add(new TreeNode("Symetric Keys"));
            securityNode.Nodes.Add(new TreeNode("Database audit specification"));

            return securityNode;
        }

        /// <summary>
        /// Add programmability node
        /// </summary>
        /// <param name="currentDb">
        /// The current db.
        /// </param>
        /// <returns>
        /// The add programmabilty.
        /// </returns>
        private TreeNode AddProgrammabilty(DatabaseInfo currentDb)
        {
            TreeNode node;

            var programmabilityNode = new TreeNode("Programmability")
                {
                    ImageIndex = 2,
                    SelectedImageIndex = 2,
                    Tag = "Programmability"
                };

            if (ConfigInstance.Config.IsProceduresVisible)
                {
                    node = this.ShowOneResult(programmabilityNode, "Stored procedures", DatabaseObjectTypes.Procedure, 3, currentDb);
                    foreach (DbObjectsDs.ProcedureRow row in currentDb.GetRawDatatable(DatabaseObjectTypes.Procedure).Rows)
                    {
                        this.ShowMoreNode(node, currentDb, 4, DatabaseObjectTypes.Procedure, string.Format("{0}.{1}", row.SchemaName, row.Name));
                    }
                }

            if (ConfigInstance.Config.IsFunctionsVisible)
            {
                node = this.ShowOneResult(programmabilityNode, "Functions", DatabaseObjectTypes.Function, 3, currentDb);
                foreach (DbObjectsDs.FunctionRow row in
                    currentDb.GetRawDatatable(DatabaseObjectTypes.Function).Rows.Cast<DbObjectsDs.FunctionRow>().Where(row => row.SchemaName != null))
                {
                    this.ShowMoreNode(node, currentDb, 4, DatabaseObjectTypes.Function, string.Format("{0}.{1}", row.SchemaName, row.Name));
                }
            }

            if (ConfigInstance.Config.IsTriggersVisible)
            {
                node = this.ShowOneResult(programmabilityNode, "Triggers", DatabaseObjectTypes.Trigger, 3, currentDb);
                foreach (DbObjectsDs.TriggerRow row in currentDb.GetRawDatatable(DatabaseObjectTypes.Trigger).Rows)
                {
                    this.ShowMoreNode(node, currentDb, 4, DatabaseObjectTypes.Trigger, row.SchemaName + "." + row.Name);
                }
            }

            if (ConfigInstance.Config.IsDefaultsVisible)
            {
                node = this.ShowOneResult(programmabilityNode, "Defaults", DatabaseObjectTypes.Default, 3, currentDb);
                foreach (DbObjectsDs.DefaultRow row in currentDb.GetRawDatatable(DatabaseObjectTypes.Default).Rows)
                {
                    this.ShowMoreNode(node, currentDb, 4, DatabaseObjectTypes.Default, string.Format("{0}.{1}", row.SchemaName, row.Name));
                }
            }

            if (ConfigInstance.Config.IsUDTVisible)
            {
                node = this.ShowOneResult(programmabilityNode, "User defined data types", DatabaseObjectTypes.UDT, 3, currentDb);
                foreach (DbObjectsDs.UDTRow row in currentDb.GetRawDatatable(DatabaseObjectTypes.UDT).Rows)
                {
                    this.ShowMoreNode(node, currentDb, 4, DatabaseObjectTypes.UDT, string.Format("{0}.{1}", row.SchemaName, row.Name));
                }
            }

            if (ConfigInstance.Config.IsRulesVisible)
            {
                node = this.ShowOneResult(programmabilityNode, "Rules", DatabaseObjectTypes.Rule, 3, currentDb);
                foreach (DbObjectsDs.RuleRow row in currentDb.GetRawDatatable(DatabaseObjectTypes.Rule).Rows)
                {
                    this.ShowMoreNode(node, currentDb, 4, DatabaseObjectTypes.Rule, string.Format("{0}.{1}", row.SchemaName, row.Name));
                }
            }

            programmabilityNode.Nodes.Add(new TreeNode("Assemblies"));
            programmabilityNode.Nodes.Add(new TreeNode("Types"));
            programmabilityNode.Nodes.Add(new TreeNode("Plan guides"));

            return programmabilityNode;
        }


        /// <summary>
        /// The show compare result.
        /// </summary>
        private void ShowCompareResult()
        {
            TreeNode serverNode;

            try
            {
                this.Cursor = Cursors.WaitCursor;

                this.diffTreeView.Nodes.Clear();
                this.diffTreeView.ImageList = this.imlDatabaseIcons;
                this.diffTreeView.HideSelection = false;

                serverNode = new TreeNode("Server")
                {
                    ImageIndex = 0,
                    SelectedImageIndex = 0,
                    Tag = new TagInfo2(DatabaseObjectTypes.Server, this.Databases, null)
                };
                this.diffTreeView.Nodes.Add(serverNode);

                var databaseNode = new TreeNode("Database")
                {
                    ImageIndex = 2,
                    SelectedImageIndex = 2,
                    Tag = new TagInfo2(DatabaseObjectTypes.Database, this.Databases, null)
                };
                serverNode.Nodes.Add(databaseNode);

                if (ConfigInstance.Config.IsTablesVisible)
                {
                    this.ShowOneResult(databaseNode, "Tables", DatabaseObjectTypes.Table);
                }

                if (ConfigInstance.Config.IsViewsVisible)
                {
                    this.ShowOneResult(databaseNode, "Views", DatabaseObjectTypes.View);
                }

                if (ConfigInstance.Config.IsProceduresVisible)
                {
                    this.ShowOneResult(databaseNode, "Stored procedures", DatabaseObjectTypes.Procedure);
                }

                if (ConfigInstance.Config.IsFunctionsVisible)
                {
                    this.ShowOneResult(databaseNode, "Functions", DatabaseObjectTypes.Function);
                }

                if (ConfigInstance.Config.IsTriggersVisible)
                {
                    this.ShowOneResult(databaseNode, "Triggers", DatabaseObjectTypes.Trigger);
                }

                if (ConfigInstance.Config.IsUsersVisible)
                {
                    this.ShowOneResult(databaseNode, "Users", DatabaseObjectTypes.User);
                }

                /*if (ConfigInstance.Config.IsRolesVisible) 
                    ShowOneResult(databaseNode,"Roles",dbObjectsTable.tblRule);*/
                if (ConfigInstance.Config.IsRulesVisible)
                {
                    this.ShowOneResult(databaseNode, "Rules", DatabaseObjectTypes.Rule);
                }

                if (ConfigInstance.Config.IsDefaultsVisible)
                {
                    this.ShowOneResult(databaseNode, "Defaults", DatabaseObjectTypes.Default);
                }

                if (ConfigInstance.Config.IsUDTVisible)
                {
                    this.ShowOneResult(databaseNode, "User defined data types", DatabaseObjectTypes.UDT);
                }

                this.diffTreeView.ExpandAll();
                this.diffTreeView.SelectedNode = this.diffTreeView.Nodes[0];
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }
        #region AddNode

        /// <summary>
        /// The show one result.
        /// </summary>
        /// <param name="databaseNode">
        /// The database node.
        /// </param>
        /// <param name="treenodeName">
        /// The treenode name.
        /// </param>
        /// <param name="dbobjectstable">
        /// The dbobjectstable.
        /// </param>
        /// <param name="imageIndex">
        /// The image index.
        /// </param>
        private void ShowOneResult(TreeNode databaseNode, string treenodeName, DatabaseObjectTypes dbobjectstable, int imageIndex = 3)
        {
            this.ShowOneResult(databaseNode, treenodeName, dbobjectstable, imageIndex, this.Databases);
        }

        /// <summary>
        /// The show one result.
        /// </summary>
        /// <param name="databaseNode">
        /// The database node.
        /// </param>
        /// <param name="treenodeName">
        /// The treenode name.
        /// </param>
        /// <param name="dbobjectstable">
        /// The dbobjectstable.
        /// </param>
        /// <param name="imageIndex">
        /// The image index.
        /// </param>
        /// <param name="currentDb">
        /// The current db.
        /// </param>
        private void ShowOneResult(TreeNode databaseNode, string treenodeName, DatabaseObjectTypes dbobjectstable, int imageIndex, Databases currentDb)
        {
            TreeNode node = this.ShowOneResultNode(treenodeName, imageIndex);
            node.Tag = new TagInfo2(dbobjectstable, currentDb, null);
            databaseNode.Nodes.Add(node);
        }

        /// <summary>
        /// The show one result.
        /// </summary>
        /// <param name="databaseNode">
        /// The database node.
        /// </param>
        /// <param name="treenodeName">
        /// The treenode name.
        /// </param>
        /// <param name="dbobjectstable">
        /// The dbobjectstable.
        /// </param>
        /// <param name="imageIndex">
        /// The image index.
        /// </param>
        /// <param name="currentDb">
        /// The current db.
        /// </param>
        /// <returns>
        /// the node of currertdb
        /// </returns>
        private TreeNode ShowOneResult(TreeNode databaseNode, string treenodeName, DatabaseObjectTypes dbobjectstable, int imageIndex, DatabaseInfo currentDb)
        {
            var node = this.ShowOneResultNode(treenodeName, imageIndex);
            node.Tag = new TagInfo2(dbobjectstable, currentDb, null);
            databaseNode.Nodes.Add(node);
            return node;
        }

        /// <summary>
        /// The show one result node.
        /// </summary>
        /// <param name="treenodeName">
        /// The treenode name.
        /// </param>
        /// <param name="imageIndex">
        /// The image index.
        /// </param>
        /// <returns>
        /// the node of result
        /// </returns>
        private TreeNode ShowOneResultNode(string treenodeName, int imageIndex)
        {
            var node = new TreeNode(treenodeName) { ImageIndex = imageIndex, SelectedImageIndex = imageIndex };
            return node;
        }

        /// <summary>
        /// The show more node.
        /// </summary>
        /// <param name="dbNode">
        /// The db node.
        /// </param>
        /// <param name="currentDb">
        /// The current db.
        /// </param>
        /// <param name="imageIndex">
        /// The image index.
        /// </param>
        /// <param name="dbobjectstable">
        /// The dbobjectstable.
        /// </param>
        /// <param name="treeNodeName">
        /// The tree node name.
        /// </param>
        private void ShowMoreNode(TreeNode dbNode, DatabaseInfo currentDb, int imageIndex, DatabaseObjectTypes dbobjectstable, string treeNodeName)
        {
            TreeNode itemNode = this.ShowOneResultNode(treeNodeName, imageIndex);
            itemNode.Tag = new TagInfo2(dbobjectstable, currentDb, null, true);
            dbNode.Nodes.Add(itemNode);
        }

        #endregion

        /// <summary>
        /// The register server.
        /// </summary>
        private void RegisterServer()
        {
            var registerServerForm = new FrmRegisterServer();
            if (registerServerForm.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            this.ShowRegisteredServers();
            this.UpdateFormView();
        }

        #region compare

        /// <summary>
        /// Starts the compare.
        /// </summary>
        private void StartCompare()
        {
            try
            {
                this.Cursor = Cursors.WaitCursor;
               
                ConfigLoader.Save(!DesignTimeHelper.IsInDesignMode, ConfigInstance.Config);

                if (this.structQuery)
                {
#if Async
                    this.LoadAsync(
                                   this.Databases.DatabaseLeft.Server.Name, 
                                   this.Databases.DatabaseLeft.Name,
                                   this.Databases.DatabaseLeft.DatabaseObjects.DatabaseInfo,
                                   this.Databases.DatabaseLeft.DatabaseObjects,
                                   SelectedDatabase.Left);
                    this.LoadAsync(
                                   this.Databases.DatabaseRight.Server.Name, 
                                   this.Databases.DatabaseRight.Name,
                                   this.Databases.DatabaseRight.DatabaseObjects.DatabaseInfo,
                                   this.Databases.DatabaseRight.DatabaseObjects,
                                   SelectedDatabase.Right);
#else
                    
                //    this.LoadSync(this.databases.DatabaseLeft.DatabaseObjects.DbObj, this.databases.DatabaseLeft.DatabaseObjects);
                //    this.LoadSync(this.databases.DatabaseRight.DatabaseObjects.DbObj, databases.DatabaseRight.DatabaseObjects);
#endif
                }

#if Async
                this.CompareAsync();
#else
                CompareSync();
#endif
                this.Databases.IsCompared = true;

                this.SetDatasetOperations();
                this.ShowCompareResult();
                this.UpdateFormView();
                this.tabControlDatabaseInfo.SelectedTab = this.tabPageDiff;
            }
            catch (Exception ex)
            {
                this.Databases.IsCompared = false;
                var errorForm = new FrmError(ex);

                Logger.Instance.Write(ex);

                errorForm.ShowDialog();
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// The compare sync.
        /// </summary>
        /// <exception cref="Exception">
        /// </exception>
        private void CompareSync()
        {
            var databaseCompare = new DatabaseCompare(this.Databases.DatabaseLeft.DatabaseObjects, this.Databases.DatabaseRight.DatabaseObjects);
            databaseCompare.Compare(ConfigInstance.Config.CompareOptions);

            this.Databases.Diff = databaseCompare.Diff;
        }

        /// <summary>
        /// The compare async.
        /// </summary>
        private void CompareAsync()
        {
            string msg = string.Format(
                "Compare databases: {0}.{1} <-> {2}.{3}",
                this.Databases.DatabaseLeft.Server.Name,
                this.Databases.DatabaseLeft.Name,
                this.Databases.DatabaseRight.Server.Name,
                this.Databases.DatabaseRight.Name);
            var wrk1 = new CompareFormThread(
                                            new frmCompareStatus(),
                                            this,
                                            msg);
            var wrk2 = new CompareWorkerThread(this.Databases.DatabaseLeft.DatabaseObjects, this.Databases.DatabaseRight.DatabaseObjects);

            var ctm = new CompareThreadManager(wrk1, wrk2);

            ctm.DatabaseCompare.OnStart += new DatabaseCompare.CompareStartEventHandler(this.CompareStartHandler);
            ctm.DatabaseCompare.OnEnd += new DatabaseCompare.CompareEndEventHandler(this.CompareEndHandler);
            ctm.DatabaseCompare.OnCompare += new DatabaseCompare.CompareEventHandler(this.CompareHandler);

            ctm.Start();

            this.Databases.Diff = ctm.DatabaseCompare.Diff;
        }

        /// <summary>
        /// The start compare.
        /// </summary>
        /// <param name="isAsk">
        /// The is ask.
        /// </param>
        private void StartCompare(bool isAsk)
        {
            if (!isAsk)
            {
                this.StartCompare();
            }
            else
            {
                var result = MessageBox.Show(AskRecompare, AskRecompare, MessageBoxButtons.YesNo);
                if (result == DialogResult.Yes)
                {
                    this.StartCompare();
                }
            }
        }

        #endregion compare

        /// <summary>
        /// Betölti az adatbázis elemeket
        /// </summary>
        /// <param name="index">
        /// </param>
        /// <param name="currentDb">
        /// The currend db
        /// </param>
        private void GetDatabaseItems(SelectedDatabase index, DatabaseInfo currentDb)
        {
            var dbObj1 = new DatabaseInfoBase();
            var dbi = new DatabaseObjects();

            dbObj1.SetConnectionnString(
                currentDb.Server.Name, 
                currentDb.Name, 
                currentDb.Server.User, 
                currentDb.Server.Password, 
                currentDb.Server.AuthType);

#if Async
            this.LoadAsync(currentDb.Server.Name, currentDb.Name, dbObj1, dbi, index);
#else
            this.LoadSync(dbObj1, dbi, index);
#endif


#if (DEBUG)
            /*string s =dbi.dbObj.dtObjects.DataSetName;
            dbi.DbObj.dtObjects.DataSetName = dbi.DbObj.dtObjects.DataSetName+"Ds";
            dbi.DbObj.dtObjects.Schema(dbi.DbObj.dtObjects.DataSetName+".xsd");
            dbi.DbObj.dtObjects.DataSetName =s;*/
#endif


            switch (index)
            {
                case SelectedDatabase.Left:
                    this.Databases.DatabaseLeft.DatabaseObjects = dbi;
                    break;

                case SelectedDatabase.Right:
                    this.Databases.DatabaseRight.DatabaseObjects = dbi;
                    break;

                default:
                    throw new DbDiffClientException("ERROR: Invalid database index! Index: " + index);
            }

            this.SetDatasetOperations();
        }

        /// <summary>
        /// The load async.
        /// </summary>
        /// <param name="serverName">
        /// The server Name.
        /// </param>
        /// <param name="databaseName">
        /// The database Name.
        /// </param>
        /// <param name="dbObj1">
        /// The db obj 1.
        /// </param>
        /// <param name="dbi">
        /// The dbi.
        /// </param>
        /// <param name="selectedDatabase">
        /// The selected Database.
        /// </param>
        private void LoadAsync(string serverName, string databaseName, DatabaseInfoBase dbObj1, DatabaseObjects dbi, SelectedDatabase selectedDatabase)
        {
            EventStatusInfoCollection eventStatusInfos = ThreadHelper.GetEventInfos(false);

            dbi.OnStart += this.LoadStartHandler;
            dbi.OnEnd += this.LoadEndHandler;
            dbi.OnItemLoadStart += this.LoadHandler;
            var tm = new ItemLoadThreadManager(new StatusFormThread(new FrmItemLoadStatus(), this, string.Format("Loading database: {0}.{1}", serverName, databaseName), eventStatusInfos), new ItemLoadThread(dbi, dbObj1, ConfigInstance.Config.CompareOptions, this.structQuery, selectedDatabase));
            tm.Start();
        }

        /// <summary>
        /// The load sync.
        /// </summary>
        /// <param name="dbObj1">
        /// The db obj 1.
        /// </param>
        /// <param name="dbi">
        /// The dbi.
        /// </param>
        private void LoadSync(DatabaseInfoBase dbObj1, DatabaseObjects dbi, SelectedDatabase selectedDatabase)
        {
            dbi.Init(dbObj1, ConfigInstance.Config.CompareOptions, false);
            dbi.SetDbObjects(selectedDatabase);
        }

        /// <summary>
        /// Letiltja a dataset műveleteket
        /// </summary>
        private void SetDatasetOperations()
        {
            /*if (this.Databases != null)
            {
                if (this.Databases.DatabaseLeft.DatabaseObjects != null)
                {
                    foreach (DataTable table in this.Databases.DatabaseLeft.DatabaseObjects.DatabaseInfo.DatabaseDataSets.Tables)
                    {
                        table.DefaultView.AllowNew = false;
                        table.DefaultView.AllowDelete = false;
                        table.DefaultView.AllowEdit = false;
                    }
                }

                if (this.Databases.DatabaseRight.DatabaseObjects != null)
                {
                    foreach (DataTable table in this.Databases.DatabaseRight.DatabaseObjects.DatabaseInfo.DatabaseDataSets.Tables)
                    {
                        table.DefaultView.AllowNew = false;
                        table.DefaultView.AllowDelete = false;
                        table.DefaultView.AllowEdit = false;
                    }
                }

                if (this.Databases.Diff != null)
                {
                    foreach (DataTable table in this.Databases.Diff.Tables)
                    {
                        table.DefaultView.AllowNew = false;
                        table.DefaultView.AllowDelete = false;
                        table.DefaultView.AllowEdit = false;
                    }
                }
             
            }*/
        }

        /// <summary>
        /// The connect db.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        private void ConnectDb(SelectedDatabase index)
        {
            this.project.IsChanged = true;

            var databaseInfo = index == SelectedDatabase.Left ? this.Databases.DatabaseLeft : this.Databases.DatabaseRight;

            if (databaseInfo.IsConnected)
            {
                string currentDb = string.Format("Current database{0}: {1} / {2}", index, databaseInfo.Server.Id,
                                                 databaseInfo.Name);
                if (MessageBox.Show(string.Format("{0}{1}Close this connection?", currentDb, Environment.NewLine),
                                    string.Format("Connect - database ({0})", index), MessageBoxButtons.YesNo,
                                    MessageBoxIcon.Exclamation) != DialogResult.Yes)
                {
                    return;
                }
            }

            var connectForm = new FrmConnectDb(databaseInfo);
            switch (connectForm.ShowDialog())
            {
                case DialogResult.OK:
                    databaseInfo = connectForm.Database;
                    databaseInfo.Connect();
                    this.Databases.IsCompared = false;
                    switch (index)
                    {
                        case SelectedDatabase.Left:
                            this.Databases.DatabaseLeft = databaseInfo;
                            break;
                        default:
                            this.Databases.DatabaseRight = databaseInfo;
                            break;
                    }

                    this.ShowDatabase(index, true);
                    this.UpdateFormView();
                    this.tabControlDatabaseInfo.SelectedTab = index == SelectedDatabase.Left
                                                                  ? this.tabPageDatabase1
                                                                  : this.tabPageDatabase2;
                    break;
            }
        }

        /// <summary>
        /// The reload database.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        private void ReloadDatabase(SelectedDatabase index)
        {
            if (this.Databases == null || Databases.DatabaseLeft == null)
            {
                return;
            }
            this.project.IsChanged = true;
            this.Databases.IsCompared = false;
            this.ShowDatabase(index, true);
            this.UpdateFormView();
            this.tabControlDatabaseInfo.SelectedTab = index == SelectedDatabase.Left ? this.tabPageDatabase1 : this.tabPageDatabase2;
        }

        /// <summary>
        /// The close database.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        private void CloseDatabase(SelectedDatabase index)
        {
            string currentDb = "Current database: ";
            if (index == SelectedDatabase.Left)
            {
                currentDb += this.Databases.DatabaseLeft.Server.Id + " / " + this.Databases.DatabaseLeft.Name;
            }
            else
            {
                currentDb += this.Databases.DatabaseRight.Server.Id + " / " + this.Databases.DatabaseRight.Name;
            }

            if (
                MessageBox.Show(currentDb + Environment.NewLine + "Are you sure?", "Close database connection",
                                MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) != DialogResult.Yes)
            {
                return;
            }

            this.project.IsChanged = true;

            if (index == SelectedDatabase.Left)
            {
                this.Databases.DatabaseLeft = new DatabaseInfo();
            }
            else
            {
                this.Databases.DatabaseRight = new DatabaseInfo();
            }

            this.Databases.IsCompared = false;
            this.Databases.Diff = null;

            this.UpdateFormView();
        }

        /// <summary>
        /// The set options.
        /// </summary>
        private void SetOptions()
        {
            var optionsForm = new FrmOptionsX();
            switch (optionsForm.ShowDialog())
            {
                case DialogResult.OK:
                    if (optionsForm.Reload)
                    {
                        var result = MessageBox.Show(AskReload, AskReload, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);

                        switch (result)
                        {
                            case DialogResult.Yes:
                                if (ConfigInstance.Config.Database1 != null)
                                {
                                    this.ReloadDatabase(SelectedDatabase.Left);
                                }

                                if (ConfigInstance.Config.Database2 != null)
                                {
                                    this.ReloadDatabase(SelectedDatabase.Right);
                                }

                                if (ConfigInstance.Config.Database1 != null && ConfigInstance.Config.Database2 != null)
                                {
                                    this.StartCompare(true);
                                }

                                break;
                        }
                    }
                    else if (optionsForm.Recompare)
                    {
                        this.StartCompare(true);
                    }
                    break;
            }

            optionsForm.Dispose();
        }

        /// <summary>
        /// Alter script generálás
        /// </summary>
        /// <param name="index">
        /// a kiindulási adatbázis indexe
        /// </param>
        private void GetAlterScript(SelectedDatabase index)
        {
            try
            {
                this.Cursor = Cursors.WaitCursor;
                DatabaseUpgrade.UpgradeDirection upgradeDirection;
                string title;
                if (index == SelectedDatabase.Left)
                {
                    title = "Alter script ->";
                    upgradeDirection = DatabaseUpgrade.UpgradeDirection.FromLeft;
                }
                else
                {
                    title = "Alter script <-";
                    upgradeDirection = DatabaseUpgrade.UpgradeDirection.FromRight;
                }


                var dbu = new DatabaseUpgrade(upgradeDirection, this.Databases.Diff, this.Databases);
                string s = dbu.Upgrade();

                var alterScriptForm = new FrmAlterScript(title, s);

                alterScriptForm.Show();


                // alterScriptForm.Dispose();
                this.Cursor = Cursors.Default;
            }
            catch (Exception e)
            {
                this.Cursor = Cursors.Default;
                var errorForm = new FrmError(e);
                errorForm.Show();
            }
        }
    }
}
